Skip to content

feat: enhance GCS upload handling with async support and improved error logging#619

Merged
jirhiker merged 1 commit intostagingfrom
api-hardening
Mar 27, 2026
Merged

feat: enhance GCS upload handling with async support and improved error logging#619
jirhiker merged 1 commit intostagingfrom
api-hardening

Conversation

@jirhiker
Copy link
Copy Markdown
Member

@jirhiker jirhiker commented Mar 27, 2026

Summary

Fixes backend lock-up behavior seen during batch field-sheet export when asset-related GCS operations hang.

Problem

During Well Batch Export, the UI loads asset data for each well before PDF generation. If GCS calls stall (upload/check/signing), API requests can hang long enough to make the export appear frozen.

Root Cause

  • POST /asset/upload runs synchronous GCS work directly inside an async route.
  • GCS client/bucket setup was repeated frequently.
  • GCS blob existence/upload/sign-url paths had no explicit time bounds.
  • Signed URL generation failures could block response completion.

What Changed

1) Prevent async event-loop blocking for uploads

  • api/asset.py
  • upload_asset now runs gcs_upload(...) via run_in_threadpool(...).

2) Reduce repeated GCS setup overhead

  • services/gcs_helper.py
  • Added @lru_cache for storage client and default bucket access.

3) Add bounded GCS operations + fail-safe signed URLs

  • services/gcs_helper.py
  • Added env-configurable timeouts:
    • GCS_LOOKUP_TIMEOUT_SECS (default 15)
    • GCS_UPLOAD_TIMEOUT_SECS (default 120)
  • Applied timeout to bucket.get_blob(...) and blob.upload_from_file(...).
  • Wrapped generate_signed_url(...) in try/except; logs warning and returns signed_url=None instead of hanging/failing entire response.

Why This Helps

Batch export depends on many asset calls. These changes make those paths more resilient and less likely to stall the request lifecycle, preventing full-export lockups from backend GCS slowness.

Validation

  • black api/asset.py services/gcs_helper.py (pass)
  • flake8 --extend-ignore=E501 api/asset.py services/gcs_helper.py (pass)
  • pytest tests/test_asset.py -q could not be executed in this environment due DB connectivity restrictions (localhost:5432 blocked in sandbox).

Notes

No API contract changes. Behavior change is defensive: when signing fails, responses still succeed with signed_url: null instead of blocking/failing.

Copilot AI review requested due to automatic review settings March 27, 2026 15:59
Copy link
Copy Markdown
Contributor

Copilot AI left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

This PR improves Google Cloud Storage (GCS) asset upload behavior in the API by moving blocking GCS operations off the event loop, adding configurable timeouts, and making signed URL generation failures non-fatal (with logging) so asset reads don’t hard-fail on transient GCS issues.

Changes:

  • Run synchronous gcs_upload in a threadpool from the async /asset/upload endpoint to avoid blocking the event loop.
  • Add cached GCS client/bucket helpers and configurable lookup/upload timeouts for GCS calls.
  • Wrap signed URL generation in try/except and emit a warning log on failure while returning signed_url=None.

Reviewed changes

Copilot reviewed 2 out of 2 changed files in this pull request and generated 2 comments.

File Description
services/gcs_helper.py Adds caching for client/bucket, introduces timeout env vars for GCS operations, and improves signed URL failure handling with logging.
api/asset.py Uses run_in_threadpool to call the synchronous GCS upload from an async route handler.

@jirhiker jirhiker merged commit 355706d into staging Mar 27, 2026
12 of 16 checks passed
@jirhiker jirhiker deleted the api-hardening branch March 27, 2026 16:31
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants